package com.example.service;

import com.example.domain.Clazz;
import com.example.domain.Student;
import com.example.repository.ClazzRepository;
import com.example.repository.StudentRepository;
import com.example.util.EasyuiResult;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service
@Slf4j
public class StudentService {
    @Autowired
    private StudentRepository studentRepository;
    @Autowired
    private ClazzRepository clazzRepository;
    
    @Autowired
    private ScoreService scoreService;
    
    /**
     * 根据clazz删除学生.
     *
     * @param clazzids 班级id
     */
    @Transactional
    public void deleteByClazzId(final List<Integer> clazzids) {
        
        log.debug("根据 (clazzid={}) 删除学生", clazzids);
        studentRepository.deleteAllByClazz_IdIn(clazzids);
    }
    
    /**
     * 分页显示学生信息 service
     *
     * @param type       类型,学生默认为2
     * @param page       当前页面,从0开始
     * @param rows       每页显示的行数
     * @param sortColumn 排序的列名
     * @param order      排序的方式,ASC/DESC
     * @param clazzid    班级的id
     * @return 分页后的学生列表
     */
    @Transactional
    public EasyuiResult<Student> list(final int type, final int page, final int rows, final String sortColumn,
                                      final String order, final int clazzid) {
        log.info("StudentService.list参数 clazzid={}", clazzid);
        
        Sort sort = new Sort(Sort.Direction.fromString(order), sortColumn);
        final PageRequest pageRequest = PageRequest.of(page, rows, sort);
        Page<Student> all;
        if (clazzid != 0) {
            //根据clazzid查询,在列表页选择班级时使用
            all = studentRepository.findAllByClazz_Id(clazzid, pageRequest);
        } else {
            //所有分页数据,没有clazzid的查询条件
            all = studentRepository.findAllByType(type, pageRequest);
        }
        
        
        final List<Student> students = all.getContent();
        
        EasyuiResult<Student> result = new EasyuiResult<>();
        result.setRows(students);
        result.setTotal(all.getTotalElements());
        return result;
    }
    
    
    /**
     * 无附加条件,查询出所有学生
     *
     * @return 所有学生列表, 无参数
     */
    public List<Student> getAllStudents() {
        return Lists.newArrayList(studentRepository.findAll());
    }
    
    /**
     * 更新或者保存,根据student的id
     * 注意,更新时的数据,
     * account(账号)信息不允许变更.
     * 如果只是 student 的 name 变化,对其他表是没有影响的
     * 如果 student 中的 班级信息(clazz)变化,会删除成绩表(score)中对应的信息.
     *
     * @param student 要保存或者更新的实体对象student
     * @return 更新或保存的结果, 用于前台判断是否成功
     */
    @Transactional
    public int update(final Student student) {
        final int id = student.getClazz().getId();
        final Optional<Clazz> clazzOptional = clazzRepository.findById(id);
        if (clazzOptional.isPresent()) {
            final Clazz clazz = clazzOptional.get();
            // student.setClazz(clazz);
            
            // 已经存在的数据,更新
            if (student.getId() > 0) {
                //从数据库中获取需要更新的数据(optional)
                final Optional<Student> optionalStudent = studentRepository.findById(student.getId());
                //从optional中取得具体的数据
                final Student savedStudent = optionalStudent.orElseGet(Student::new);
                if (!(savedStudent.getId() > 0)) {
                    log.error("更新(student)数据库中已有的数据,但是经过查询并不存在,需要更新的id={}", student.getId());
                    throw new NullPointerException();
                }
                if (!(savedStudent.getClazz().getId() > 0)) {
                    log.error("更新(student)数据库中已有的数据,但是经过查询,其clazz并不存在,需要更新的id={}", student.getId());
                    throw new NullPointerException();
                }
                if (student.getClazz().getId() == clazz.getId()) {
                    //此时更新数据中clazz信息.
                    // 1. 不删除core中的数据信息.保存历史记录
                    // 2. 删除core中的数据信息,不会保存历史数据
                    //两种方式都能保证数据的完整性
                    //默认选1,什么都不做
                    
                }
            }
            student.setClazz(clazz);
            // 要保存的数据,生成account信息
            if (student.getAccount() == null) {
                log.debug("新增数据,为student(name={})设置account信息", student.getName());
                final String generateMaxAccount = this.generateAccount(id);
                String account = "";
                //当
                if (generateMaxAccount == null || generateMaxAccount.length() == 0) {
                    log.debug("clazz(name={})目前还没有学生数据" + clazz.getName());
                    account = clazz.getName().replaceAll("\\D", "") + "001";
                } else {
                    account = generateMaxAccount;
                }
                student.setAccount(account + "001");
            }
            
            log.debug("保存或更新学生数据student(id={},name={},account={},clazzid={})", student.getId(),
                    student.getAccount(), student.getName(), clazz.getId());
            final Student save = studentRepository.save(student);
            return save.getId();
        }
        
        //使用optional(java 8)方法,如果执行到此处,说明数据库执行有误
        log.error(" StudentService.update() 保存或更新失败,请检查数据库的相关操作!!");
        return 0;
        
    }
    
    @Transactional
    public void delete(final int[] ids) {
        log.debug("删除学生信息,ids={}", ids);
        //彻底删除学生信息时,为了维护完整性,score表中的成绩信息也要一并删除
        scoreService.deleteByStudentId(ids);
        log.debug("删除成绩表中的相关信息 studentids={}", ids);
        studentRepository.deleteByIdIn(ids);
    }
    
    /**
     * 根据clazzid生成本班级对应的学号信息,默认最大值加+1
     * 注意,如果班级(clazzid)对应的学生没有,第一个加进来的时返回0
     *
     * @param clazzid 班级id
     * @return 学号(account)的最大值
     */
    private long findMaxAccount(int clazzid) {
        try {
            return studentRepository.findMaxAccount(clazzid);
        } catch (Exception e) {
            return 0;
        }
    }
    
    
    /**
     * 根据clazzid生成account
     * 这种方式不完善,只是为了能更快显示出student所在的班级.
     * 如果为了达到高可用和分布式的要求,可以使用snowshake的方式生成.
     *
     * @param clazzid 班级id
     * @return 生成的account
     */
    public String generateAccount(int clazzid) {
        final long maxAccount = this.findMaxAccount(clazzid);
        if (maxAccount > 0) {
            return maxAccount + 1 + "";
        }
        return "";
        
    }
}
